package com.yanggu.redisson.controller;

import org.redisson.api.RCountDownLatch;
import org.redisson.api.RLock;
import org.redisson.api.RPermitExpirableSemaphore;
import org.redisson.api.RSemaphore;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.concurrent.TimeUnit;

/**
 * 测试使用Redisson锁数据类型
 */
@RestController
@RequestMapping("/test-lock")
public class TestLockController {

    @Autowired
    @Qualifier("test-lock")
    private RLock lock;

    @Autowired
    @Qualifier("test-semaphore")
    private RSemaphore semaphore;

    @Autowired
    @Qualifier("test-permit-explorable-semaphore")
    private RPermitExpirableSemaphore permitExplorableSemaphore;

    @Autowired
    @Qualifier("test-count-down-latch")
    private RCountDownLatch countDownLatch;

    //基于Redis的String实现的分布式锁
    @GetMapping("/test1")
    public void test1() {
        lock.lock();
        try {
            System.out.println("test1");
        } finally {
            lock.unlock();
        }
    }

    //基于Redis的String实现的分布式信号量。value就是具体的值，acquire减少令牌值，release增加令牌值
    @GetMapping("/test2")
    public void test2() {
        //设置信号量总数
        boolean b = semaphore.trySetPermits(3);
        System.out.println("b = " + b);
        //获取令牌
        boolean result = semaphore.tryAcquire(2);
        if (result) {
            try {
                System.out.println("获取到令牌");
                boolean b1 = semaphore.tryAcquire(2);
                System.out.println("b1 = " + b1);
            } finally {
                //释放令牌
                semaphore.release(2);
            }
        }
    }

    //和test2的区别是，RSemaphore需要在finally中释放，否则会一直阻塞。有可能服务宕机，没有执行finally方法，令牌一直没有释放
    //使用String存储令牌的数量，使用ZSet存储数据，score是到期时间，member是令牌id
    //支持过期自动释放。但并不是使用定时任务扫描ZSet实现的，也不是使用发布订阅生成定时任务实现，而是在获取，释放时，实现
    //这是一种饿汉式的思想。
    @GetMapping("/test3")
    public void test3() throws InterruptedException {
        boolean b = permitExplorableSemaphore.trySetPermits(3);
        System.out.println("b = " + b);
        //获取令牌，返回令牌id，等待10s，20s后自动释放
        String permitId = permitExplorableSemaphore.tryAcquire(10L, 20L, TimeUnit.SECONDS);
        if (permitId != null) {
            try {
                System.out.println("获取到令牌");
                //更新令牌的过期时间
                permitExplorableSemaphore.updateLeaseTime(permitId, 10L, TimeUnit.SECONDS);
            } finally {
                //释放令牌
                permitExplorableSemaphore.release(permitId);
            }
        }
    }

    //底层为Redis的String类型，初始值就是count，countDown减少count值，await等待，超时返回false
    @GetMapping("/test4")
    public void test4() throws InterruptedException {
        //设置初始值
        boolean b = countDownLatch.trySetCount(3);
        System.out.println("b = " + b);
        //等待
        boolean result = countDownLatch.await(100L, TimeUnit.SECONDS);
        if (result) {
            System.out.println("countDownLatch.await() = " + result);
        }
    }

    @GetMapping("/test5")
    public void test5() {
        countDownLatch.countDown();
    }

}
